/**
 * 
 */
package instant.mail;

import java.util.ArrayList;
import java.util.Arrays;

import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;

/**
 * @author qiangli
 * 
 */
public class RecipientsActivity extends ListActivity implements OnClickListener {

	private class InitTask extends AsyncTask<Void, Void, Void> {

		@Override
		protected void onCancelled() {
			setProgressBarIndeterminateVisibility(false);
		}

		@Override
		protected void onPreExecute() {
			setProgressBarIndeterminateVisibility(true);
		}

		@Override
		protected Void doInBackground(Void... params) {
			loadAddresses();
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			try {
				updateUi();
			} finally {
				setProgressBarIndeterminateVisibility(false);
			}
		}
	}

	private static final int DIALOG_SAVEAS = 1;
	private static final String TAG = "RecipientsActivity";
	private static final int DIALOG_VIEWSELECTED = 2;
	
	private static final int RC_VOICEINPUT_SAVEAS = 1;
	
	private ArrayAdapter<EmailAddress> adapter;

	private ArrayList<EmailAddress> addresses = new ArrayList<EmailAddress>();
	// set to new list name if list is selected/created,
	// clear if select all, none, other or any item is un/checked
	private String listname;
	private EmailAddress[] emailList;

	//
	private EditText editName;
	private TextView recipientsText;
	private MenuItem saveasMenuItem;
	private MenuItem selectMenuItem;
	private View buttons;
	private View footer;
	private MenuItem exportMenuItem;
	private MenuItem importMenuItem;
	//private boolean restored;
	private RadioButton starButton0;
	private RadioButton starButton1;
	private RadioButton starButton2;
	private ArrayList<String> listNames;
	private MenuItem viewMenuItem;
	private ArrayAdapter<NameIndex> viewSelectedItems;
	
	private void doLists(String n) {
		String[] emails = ContactUtils.getEmail(this, n);
		int len = emails.length;
		//
		ListView v = getListView();
		v.clearChoices();
		int pos = 0;
		//
		for (EmailAddress a : addresses) {
			boolean ck = false;
			if (len != 0) {
				String ea = a.address;
				for (int i = 0; i < len; i++) {
					if (emails[i].equals(ea)) {
						ck = true;
						break;
					}
				}
			}
			v.setItemChecked(pos++, ck);
		}
		//
		listname = n;
		//
		refreshUi(v, true, n);
	}

	/*
	 * save new list
	 */
	private void doSave(String name, boolean contact, int star) {
		ArrayList<EmailAddress> al = getSelectedEmails();
		String[] emails = Utils.toStringArray(al);
		name = Utils.ensureListName(name);
		if (contact) {
			ContactUtils.saveAsContact(this, name, star, emails);
		} else {
			ContactUtils.addList(this, name, star, emails);
		}

		listname = name;
		//
		ListView v = getListView();
		refreshUi(v, false, name);
	}

	/*
	 * Select all, none, or other
	 * 
	 * @param id
	 */
	private void doSelect(int id) {
		// clear listname
		listname = null;
		//
		final ListView v = getListView();
		switch (id) {
		case R.id.recipients_select_none_menu_id: {
			v.clearChoices();
			refreshUi(v, false, null); // donot show action as there is no
			// selection
			return;
		}
		case R.id.recipients_select_all_menu_id: {
			int cnt = v.getCount();
			for (int i = 0; i < cnt; i++) {
				v.setItemChecked(i, true);
			}
			refreshUi(v, true, null);
			return;
		}
		case R.id.recipients_select_other_menu_id: {
			int cnt = v.getCount();
			for (int i = 0; i < cnt; i++) {
				boolean ck = v.isItemChecked(i);
				v.setItemChecked(i, !ck);
			}
			refreshUi(v, true, null);
			return;
		}
		}
	}

	private int getCount() {
		return adapter.getCount();
	}

	private int getSelectedCount() {
		SparseBooleanArray ps = getListView().getCheckedItemPositions();
		int size = adapter.getCount();
		int cnt = 0;
		for (int i = 0; i < size; i++) {
			if (ps.get(i)) {
				cnt++;
			}
		}
		return cnt;
	}

	private ArrayList<EmailAddress> getSelectedEmails() {
		SparseBooleanArray ps = getListView().getCheckedItemPositions();
		ArrayList<EmailAddress> ck = new ArrayList<EmailAddress>();
		int size = adapter.getCount();
		for (int i = 0; i < size; i++) {
			if (ps.get(i)) {
				ck.add(adapter.getItem(i));
			}
		}
		return ck;
	}

	private boolean hasSelected() {
		SparseBooleanArray ps = getListView().getCheckedItemPositions();
		int size = adapter.getCount();
		for (int i = 0; i < size; i++) {
			if (ps.get(i)) {
				return true;
			}
		}
		return false;
	}

	private void updateUi() {
		// set to reload
		getListView().setAdapter(adapter);
		//
		EmailAddress[] el = emailList;
		ListView v = getListView();
		v.clearChoices();
		int pos = 0;
		for (EmailAddress a : addresses) {
			boolean ck = false;
			if (el != null) {
				for (int i = 0; i < el.length; i++) {
					if (el[i].equals(a)) {
						ck = true;
						break;
					}
				}
			}
			v.setItemChecked(pos++, ck);
		}
		// do not show actions unless triggered by user
		refreshUi(v, false, listname);
	}

	private void loadAddresses() {
		ContactUtils.loadAddresses(this, addresses);
		// merge addresses from intent
		if (emailList != null) {
			for (EmailAddress a : emailList) {
				if (!addresses.contains(a)) {
					addresses.add(a);
				}
			}
		}
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (Constants.DEBUG_ENABLED) {
			Log.d(TAG, "onCreate: " + savedInstanceState);
		}
		//
		requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
		requestWindowFeature(Window.FEATURE_LEFT_ICON);
		setContentView(R.layout.recipients);
		//
		adapter = new ArrayAdapter<EmailAddress>(this,
				R.layout.recipients_item_multiple_choice, addresses);

		setProgressBarIndeterminate(true);
		//
		final ListView lv = getListView();
		lv.setAdapter(adapter);
		lv.setItemsCanFocus(false);
		lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
		//
		setTitle(R.string.app_recipients);
		getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
				R.drawable.etalk25);
		//
		buttons = findViewById(R.id.buttons);
		buttons.setVisibility(View.GONE);
		Button save = (Button) findViewById(R.id.button_savelist);
		save.setOnClickListener(this);
		//
		footer = findViewById(R.id.footer);
		//
		addresses.clear();
		if (savedInstanceState != null) {
			restore();
			updateUi();
		} else {
			init();
			new InitTask().execute();
		}
		//
		if (Constants.DEBUG_ENABLED) {
			Log.d(TAG, "listname: " + listname + " emailList: " + emailList);
		}
	}

	@SuppressWarnings("unchecked")
	private void restore() {
		Object[] obj = (Object[]) getLastNonConfigurationInstance();
		listname = (String) obj[0];
		ArrayList<EmailAddress> el = (ArrayList<EmailAddress>) obj[1];
		emailList = (el == null ? null : el.toArray(new EmailAddress[0]));
		ArrayList<EmailAddress> al = (ArrayList<EmailAddress>) obj[2];
		if (al != null) {
			addresses.addAll(al);
		}
	}

	private void init() {
		try {
			addresses.clear();
			//
			Intent i = getIntent();
			if (i == null) {
				return;
			}
			Bundle extras = i.getExtras();
			if (extras == null) {
				return;
			}
			// listname
			listname = (String) extras.get(EtalkIntent.EXTRA_LISTNAME);

			// email list
			String emails = (String) extras.get(EtalkIntent.EXTRA_EMAILS);
			if (emails == null) {
				return;
			}
			emailList = toEmailAddress(emails);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private EmailAddress[] toEmailAddress(String emails)
			throws AddressException {
		InternetAddress[] list = InternetAddress.parse(emails);
		int len = list.length;
		EmailAddress[] al = new EmailAddress[len];
		for (int ix = 0; ix < len; ix++) {
			InternetAddress ia = list[ix];
			al[ix] = new EmailAddress(ia.getAddress(), ia.getPersonal());
		}
		return al;
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DIALOG_SAVEAS: {
			return createSaveAsDialog();
		}
		case DIALOG_VIEWSELECTED:
			return createViewSelectedDialog();
		default:
		}
		return null;
	}

	private Dialog createViewSelectedDialog() {
		final AlertDialog.Builder b = new AlertDialog.Builder(this);
		b.setTitle(R.string.dia_recipients_view);
		viewSelectedItems = new ArrayAdapter<NameIndex>(
				this, R.layout.index_dialog_item);
		b.setAdapter(viewSelectedItems, new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				NameIndex i = (NameIndex) viewSelectedItems.getItem(which);
				if (i == null) {
					return;
				}
				ListView v = getListView();
				v.setSelected(false);
				v.setSelection(i.pos);
			}
		});
		final AlertDialog d = b.create();
		return d;
	}

	private Dialog createSaveAsDialog() {
		LayoutInflater li = LayoutInflater.from(this);
		final View v = li.inflate(R.layout.contact_saveas, null);
		editName = (EditText) v.findViewById(R.id.contact_saveas_name);
		final ImageButton viBtn = (ImageButton) v.findViewById(R.id.contact_saveas_name_voiceinput);
		if (Utils.canSpeak(this)) {
			viBtn.setOnClickListener(this);
			viBtn.setEnabled(true);
			viBtn.setVisibility(View.VISIBLE);
		} else {
			viBtn.setEnabled(false);
			viBtn.setVisibility(View.GONE);
		}
		//
		recipientsText = (TextView) v
				.findViewById(R.id.contact_saveas_recipients);
		starButton0 = (RadioButton) v.findViewById(R.id.contact_saveas_star0);
		starButton1 = (RadioButton) v.findViewById(R.id.contact_saveas_star1);
		starButton2 = (RadioButton) v.findViewById(R.id.contact_saveas_star2);
		final CheckBox type = (CheckBox) v
				.findViewById(R.id.contact_saveas_type);
		// back forward compatible
		// hide type for Android 2.0 and only allow local list
		// superstar only for local list
		final boolean newapi = (ContactAdapter.newContactAPI);
		type.setVisibility(newapi ? View.GONE : View.VISIBLE); 
		type.setChecked(false); //
		final boolean use2 = (newapi || !type.isChecked());
		starButton2.setVisibility(use2 ? View.VISIBLE : View.INVISIBLE);
		type.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			public void onCheckedChanged(CompoundButton b, boolean isChecked) {
				starButton2.setVisibility(isChecked ? View.INVISIBLE : View.VISIBLE);
				if (isChecked) {
					if (starButton2.isChecked()) {
						starButton1.setChecked(true);
					}
				}
			}});
		//
		final AlertDialog d = new AlertDialog.Builder(this)
				.setTitle(R.string.dia_recipients_saveas).setView(v)
				.setPositiveButton(R.string.button_save,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
								try {
									String n = editName.getText()
											.toString();
									boolean ck = (type.isChecked() && !newapi);
									int star = 1; //default to one star
									if (starButton0.isChecked()) {
										star = 0;
									} else if (starButton1.isChecked()) {
										star = 1;
									} else if (starButton2.isChecked()) {
										star = 2;
									}
									doSave(n, ck, star);
									//
									//
									toast(R.string.msg_saved,
											Toast.LENGTH_SHORT);
								} catch (Exception e) {
									toast(R.string.msg_fail,
											e.getMessage(),
											Toast.LENGTH_LONG);
								}
							}
						}).setNegativeButton(R.string.button_cancel,
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int which) {
							}
						}).setOnCancelListener(new OnCancelListener() {
					public void onCancel(DialogInterface arg) {
					}
				}).create();
		//disable save if duplicate name
		//http://code.google.com/p/android/issues/detail?id=6360
		//getButton returns null. get it after dialog is shown instead - more expensive
		//final Button b1 = d.getButton(Dialog.BUTTON_POSITIVE);
		editName.addTextChangedListener(new TextWatcher() {
			public void afterTextChanged(Editable ed) {
				Button b1 = d.getButton(Dialog.BUTTON_POSITIVE); //TODO remove after (#6360) bug fix
				String t = ed.toString();
				if (TextUtils.isEmpty(t)) {
					b1.setEnabled(false);
					return;
				}
				t = Utils.ensureListName(t);
				boolean dup = (listNames != null && listNames.contains(t));
				b1.setEnabled(dup == false);
			}
			public void beforeTextChanged(CharSequence arg0, int arg1,
					int arg2, int arg3) {
			}
			public void onTextChanged(CharSequence s, int start,
					int before, int count) {
			}
		});
		return d;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.recipients_options, menu);
		saveasMenuItem = menu.findItem(R.id.recipients_save_menu_id);
		viewMenuItem = menu.findItem(R.id.recipients_view_menu_id);
		selectMenuItem = menu.findItem(R.id.recipients_select_menu_id);
		//
		exportMenuItem = menu.findItem(R.id.recipients_export_opt_menu_id);
		importMenuItem = menu.findItem(R.id.recipients_import_opt_menu_id);
		return true;
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			doFinish();
			return true;
		} else {
			return super.onKeyDown(keyCode, event);
		}
	}

	private void doFinish() {
		Intent data = new Intent();
		ArrayList<EmailAddress> emails = getSelectedEmails();
		if (emails.size() > 0) {
			data.putExtra(EtalkIntent.EXTRA_EMAILS, Utils.toString(emails));
		}
		if (listname != null) {
			data.putExtra(EtalkIntent.EXTRA_LISTNAME, listname);
		}
		//
		setResult(RESULT_OK, data);
		finish();
		//
		if (Constants.DEBUG_ENABLED) {
			Log.d(TAG, "doFinish " + data);
		}
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		// list name and emails out of sync, clear it
		listname = null;
		//
		int sc = getSelectedCount();
		updateTitle(sc, listname);
		showOrHideActions(sc > 0);
	}

	private void showActions() {
		buttons.setVisibility(View.VISIBLE);
		footer.setVisibility(View.GONE);
	}

	private void hideActions() {
		buttons.setVisibility(View.GONE);
		footer.setVisibility(View.VISIBLE);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (resultCode == RESULT_OK) {
			switch(requestCode) {
			case RC_VOICEINPUT_SAVEAS:
				String vi = data.getStringExtra(EtalkIntent.EXTRA_INPUT);
				editName.setText(vi);
				break;
			default:
			}
		}
	}

	public void onClick(View v) {
		int id = v.getId();
		switch (id) {
		case R.id.button_savelist:
			doCreateList();
			break;
		case R.id.contact_saveas_name_voiceinput:
			doSaveAsVoiceInput();
			break;
		}
	}

	private void doSaveAsVoiceInput() {
		Intent i = new Intent(this, VoiceInputActivity.class);
		String t = getString(R.string.prompt_name);
		String s = editName.getText().toString();
		i.putExtra(EtalkIntent.EXTRA_TITLE, t);
		i.putExtra(EtalkIntent.EXTRA_INPUT, s);
		startActivityForResult(i, RC_VOICEINPUT_SAVEAS);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		int id = item.getItemId();
		switch (id) {
		case R.id.recipients_save_menu_id:
			doCreateList();
			break;
		case R.id.recipients_view_menu_id:
			doViewSelected();
			break;
		case R.id.recipients_import_opt_menu_id:
			doImport();
			break;
		case R.id.recipients_export_opt_menu_id:
			doExport();
			break;
		case R.id.recipients_select_all_menu_id:
		case R.id.recipients_select_none_menu_id:
		case R.id.recipients_select_other_menu_id:
			doSelect(id);
			break;
		case R.id.recipients_select_menu_id:
			break;
		default:
			// lists
			String n = item.getTitle().toString();
			doLists(n);
			break;
		}
		return true;
	}

	private void doViewSelected() {
		showDialog(DIALOG_VIEWSELECTED);
	}

	private void doImport() {
		// extract and sort email addresses from clipboard
		// append to the end of the list
		String[] sa = Utils.getEmailFromClipboard(this);
		Arrays.sort(sa);
		//
		int cnt = 0;
		if (sa != null) {
			for (String s : sa) {
				EmailAddress a = new EmailAddress(s, s);
				if (!addresses.contains(a)) {
					addresses.add(a);
					cnt++;
				}
			}
		}
		//
		CharSequence txt = null;
		if (cnt == 0) {
			txt = getString(R.string.msg_pasted_none);
		} else {
			updateUi();
			//
			txt = getString(R.string.msg_pasted, cnt);
		}
		Toast.makeText(this, txt, Toast.LENGTH_SHORT).show();
	}

	private void doExport() {
		ArrayList<EmailAddress> al = getSelectedEmails();
		String s = Utils.toString(al);
		Utils.copyToClipboard(this, s);
		int cnt = al.size();
		//
		CharSequence txt = getString(R.string.msg_copied, cnt);
		Toast.makeText(this, txt, Toast.LENGTH_SHORT).show();
	}

	private void doCreateList() {
		hideActions();
		//
		showDialog(DIALOG_SAVEAS);
	}

	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		switch (id) {
		case DIALOG_SAVEAS: {
			ArrayList<EmailAddress> el = getSelectedEmails();
			String s = Utils.toString(el);
			listNames = getListNames();
			String n = Utils.makeDefaultListName(s, listNames);
			editName.setText(n);
			recipientsText.setText(s);
			break;
		}
		case DIALOG_VIEWSELECTED: {
			viewSelectedItems.clear();
			SparseBooleanArray ps = getListView().getCheckedItemPositions();
			int size = adapter.getCount();
			for (int i = 0; i < size; i++) {
				if (ps.get(i)) {
					EmailAddress ea = adapter.getItem(i);
					NameIndex ni = new NameIndex();
					ni.name = ea.toString();
					ni.pos = i;
					viewSelectedItems.add(ni);
				}
			}
			break;
		}
		}
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		boolean sel = hasSelected();
		saveasMenuItem.setEnabled(sel);
		viewMenuItem.setEnabled(sel);
		//
		ArrayList<String> l = getListNames();
		int size = l.size();
		Menu sub = selectMenuItem.getSubMenu();
		sub.setGroupVisible(R.id.SELECT_MENU, true);
		sub.setGroupVisible(R.id.LIST_MENU, size > 0);
		sub.removeGroup(R.id.LIST_MENU);
		for (int i = 0; i < size; i++) {
			sub.add(R.id.LIST_MENU, Menu.NONE, i, l.get(i));
		}
		//
		exportMenuItem.setEnabled(sel);
		boolean imp = (Utils.noEmailOnClipboard(this) == false);
		importMenuItem.setEnabled(imp);
		//
		return true;
	}

	@Override
	public Object onRetainNonConfigurationInstance() {
		Object[] obj = new Object[3];
		obj[0] = listname;
		obj[1] = getSelectedEmails();
		obj[2] = addresses;
		return obj;
	}

	private ArrayList<String> getListNames() {
		ArrayList<String> lists = new ArrayList<String>();
		ContactUtils.loadMailLists(this, lists);
		return lists;
	}

	private void refreshUi(ListView v, boolean show, String name) {
		int sc = getSelectedCount();
		updateTitle(sc, name);
		showOrHideActions(show && sc > 0);
		v.requestLayout();
	}

	private void showOrHideActions(boolean b) {
		if (b) {
			showActions();
		} else {
			hideActions();
		}
	}

	private void toast(int resId, int duration) {
		Toast.makeText(this, resId, duration).show();
	}

	private void toast(int resId, String arg, int duration) {
		CharSequence text = getString(resId, arg);
		Toast.makeText(this, text, duration).show();
	}

	private void updateTitle(int sc, String ln) {
		int tc = getCount();
		String t = (ln == null ? getString(R.string.title_recipients_nolist,
				sc, tc) : getString(R.string.title_recipients, sc, tc, ln));
		setTitle(t);
	}
}

//

// 2.0
// ArrayList<EmailAddress> emails = getSelectedEmails();
// String s = toString(emails);
// String n = Utils.makeDefaultListName(s, lists);
// Intent i = new Intent(Intent.ACTION_INSERT);
// i.putExtra(ContactsContract.Contacts.STARRED, 1);
// i.putExtra(ContactsContract.Intents.Insert.NAME,n);
// i.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
// startActivity(i);
